using System;
using Microsoft.SharePoint;

namespace SharePoint.DataMapper
{
	/// <summary>
	/// WebContext class.
	/// </summary>
	/// <example>
	/// <code>using (WebContext context = new WebContext("http://localhost/"))
	/// {
	///		Guid webId = context.Web.Id;
	/// }
	/// </code> 
	/// </example>
	public class WebContext : IDisposable
	{
		private SPWeb _web;
		private SPSite _site;

		/// <summary>
		/// Initializes a new instance of the <see cref="WebContext"/> class.
		/// </summary>
		/// <param name="webUrlOrId">Absolute URL of the Web.</param>
		public WebContext(string webUrlOrId)
		{
			_disposed = false;
			_site = Service.GetSite(webUrlOrId);
			_web = Service.GetWeb(_site, string.Empty);
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="WebContext"/> class.
		/// </summary>
		/// <param name="siteUrlOrId">Full URL to the root Web site of the collection.</param>
		/// <param name="webUrlOrId">Absolute URL of the Web.</param>
		public WebContext(string siteUrlOrId, string webUrlOrId)
		{
			_disposed = false;
			_site = Service.GetSite(siteUrlOrId);
			_web = Service.GetWeb(_site, webUrlOrId);
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="WebContext"/> class.
		/// </summary>
		/// <param name="siteId">The site id.</param>
		/// <param name="webId">The web id.</param>
		public WebContext(Guid siteId, Guid webId)
		{
			_disposed = false;
			_site = Service.GetSite(siteId.ToString());
			_web = Service.GetWeb(Site, webId.ToString());
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="WebContext"/> class.
		/// </summary>
		/// <param name="web">The web.</param>
		public WebContext(SPWeb web)
		{
			_disposed = false;
			_site = web.Site;
			_web = web;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="WebContext"/> class.
		/// </summary>
		/// <param name="site">The site.</param>
		/// <param name="web">The web.</param>
		public WebContext(SPSite site, SPWeb web)
		{
			_disposed = false;
			_site = site;
			_web = web;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="WebContext"/> class.
		/// </summary>
		/// <param name="webContext">The web context.</param>
		protected WebContext(WebContext webContext)
		{
			_disposed = false;
			_site = webContext.Site;
			_web = webContext.Web;
		}

		/// <summary>
		/// Gets the site.
		/// </summary>
		/// <value>The <see cref="SPSite"/> object. Can be null.</value>
		public SPSite Site
		{
			get
			{
				CheckDisposed();
				return _site;
			}
		}

		/// <summary>
		/// Gets the web.
		/// </summary>
		/// <value>The <see cref="SPWeb"/> object. Can be null.</value>
		public SPWeb Web
		{
			get
			{
				CheckDisposed();
				return _web;
			}
		}

		/// <summary>
		/// Reload context. Create new instances of SPWeb and SPSite objects.
		/// </summary>
		public void Reload()
		{
			CheckDisposed();
			string siteId = _site.ID.ToString();
			string webId = _web.ID.ToString();
			Close();
			_site = Service.GetSite(siteId);
			_web = Service.GetWeb(_site, webId);
		}
        
		/// <summary>
		/// Close context.
		/// </summary>
		public void Close()
		{
			if (null != _web)
			{
				_web.Close();
				_web = null;
			}
			if (null != _site)
			{
				_site.Close();
				_site = null;
			}
		}

		#region [ Dispose pattern ]

		/// <summary>
		/// Destructor
		/// </summary>
		~WebContext()
		{
			Dispose(false);
		}

		/// <summary>
		/// Track whether the Dispose method has been called.
		/// </summary>
		private bool _disposed;

		/// <summary>
		/// Releases all resources used by the data source object.
		/// </summary>
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		/// <summary>
		/// Helper method to support resource disposal.
		/// </summary>
		/// <param name="disposing">Indicates the source of the dispose call.</param>
		protected virtual void Dispose(bool disposing)
		{
			if (!_disposed)
			{
				if (disposing)
				{
					Close();
				}
			}
			_disposed = true;
		}

		/// <summary>
		/// Helper method to check for object disposal.
		/// </summary>
		/// <exception cref="ObjectDisposedException"><c>ObjectDisposedException</c>.</exception>
		protected void CheckDisposed()
		{
			if (_disposed)
				throw new ObjectDisposedException(null);
		}

		#endregion

	}
}